import { formatTime2View, formatTime2DB, formatDate2View, formatDate2DB } from '/@/utils/formatTime.js';
import {
	formatID,
	formatPhoneNumber,
	formatNumber,
	getLocalStorage,
	getVuex,
	nanTransformZero,
	booleanNot,
	formatRemoveDecimal,
	getObjAttr,
} from '/@/utils/formatPrivacyData.js';
import EnumOptions from '../../Datas/enum_options.js';
import Lxy_params_mgr from '/@/components/Linxyun/custom/CustomCommon/lxy_params_mgr.js';
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { createDDE_SA } from '/@/utils/stringUtil';
import localforage from 'localforage';
import { functions } from 'lodash';

const DDE_SA = createDDE_SA(BASE_API.ENT_CODE || 0, 0, 0);
const headers = { 'DDE-SA': DDE_SA, 'Content-Type': 'application/json;charset=UTF-8' };
const strFuncMap = {
	time2View: formatTime2View,
	time2Data: formatTime2DB,
	date2View: formatDate2View,
	date2Data: formatDate2DB,
	formatID: formatID,
	formatPhoneNumber: formatPhoneNumber,
	formatNumber: formatNumber,
	getLocalStorage: getLocalStorage,
	getVuex: getVuex,
	nanTransformZero: nanTransformZero,
	booleanNot,
	formatRemoveDecimal,
};

// label函数: 获得枚举变量对应的名称, 参数： label.EnumName, value, 返回 value对应的label值, 斜杠[/]分割
function callFunc(funcName, params) {
	if (!funcName || funcName === '') {
		console.error('[Error][callFunc]The func no defined.');
		return null;
	}

	if (funcName.indexOf('label.') === 0) {
		return lableFunc(funcName, params);
	}

	if (localStorage.getItem('strFuncMap')) {
		const func = JSON.parse(localStorage.getItem('strFuncMap'));
		console.log('funcfuncfunc', func);
		// 如果本地的函数不在设定的函数中，那么添加进去
		for (const key in func) {
			if (!strFuncMap[key]) {
				// func 里的函数格式是 "xxx":"'xxx'",所以需要截取1~length-1
				strFuncMap[key] = new Function(`return ${func[key].substring(1, func[key].length - 1)}`)();
			}
		}
	}

	if (!strFuncMap[funcName]) {
		console.error('[Error][callFunc]Func is undefined, func: ', strFuncMap, funcName);
		return null;
	}
	let res = strFuncMap[funcName](params);
	if (res === undefined || res === null) {
		console.error('[Error][callFunc]Call func fail: ', funcName, params);
		return null;
	}

	return res;
}

function lableFunc(funcName, params) {
	// $label.EnumName{var}, funcName: label.EnumName, params: 以逗号分割的参数列表
	let enumName = funcName.substr(6);
	if (!enumName || enumName === '') {
		console.error('[Error][callFunc][label]Enum name no defined: ', funcName);
		return null;
	}

	if (!params || params === '') {
		console.error('[Error][callFunc][label]Enum value no defined: ', params);
		return null;
	}
	const values = params.split(',');
	let options = EnumOptions.instance().getOptions(enumName);
	console.log('optionsoptions', options);
	if (options === null) {
		console.error('[Error][callFunc][label]Enum is not exist: ', enumName);
		return null;
	}

	let lables = [];
	if (!getLables(options, values, 0, lables)) {
		return null;
	}
	return lables.join('/');
}

function getLables(options, values, index, lables) {
	if (index === values.length) {
		return true;
	}
	if (!options || options.length === 0) {
		return false;
	}

	let res = true;
	for (let i = 0; i < options.length; i++) {
		if (options[i].value === values[index]) {
			lables.push(options[i].label);
			if (options[i].children) {
				res = getLables(options[i].children, values, index + 1, lables);
			}
			if (res) {
				return true;
			}
			lables.pop();
		}
	}
	return false;
}

class Lxy_expression {
	// 先调用 toSuffixExp 转换成后缀表达式，如果是字符串拼接(以两个双引号开头 "")，则不变;
	// 然后再调用 calcSuffixExp 进行计算或字符串拼接
	static toSuffixExp(expression) {
		// 转换为后缀表达式
		if (!expression) {
			return '';
		}
		// 如果表达式是以两个双引号开头 ""，则不变
		if (expression.length > 3 && expression[0] === '"' && expression[1] === '"') {
			return expression;
		}

		const stack = [];
		let data = '';
		let suffixExp = '';
		let priority = 0; // 权重
		let tmp;
		// 遍历表达式
		for (let i = 0; i < expression.length; i++) {
			// 如果表达式内有下面这些符号且相邻的也是符号
			if (['|', '&', '=', '!', '>', '<'].includes(expression[i]) && ['|', '&', '='].includes(expression[i + 1])) {
				// 计算权重
				priority = Lxy_expression.getPriority(expression[i] + expression[i + 1]);
				i++;
			} else {
				priority = Lxy_expression.getPriority(expression[i]);
			}
			// 平普通字符权重为0
			if (priority === 0) {
				// 操作数;
				data = data + expression[i];
				continue;
			}

			// "12 * (3 + 4) - 6 + 8 / 2"
			// 操作符或者是 括号;
			data = Lxy_expression.trim(data);
			console.log('data:', data);
			if (data !== '') {
				if (Lxy_expression.isData(data) === false) {
					// 无效数字;
					console.log('To suffix expression fail, data is invalid, data:', data);
					return '';
				}
				// 后缀表达式
				suffixExp = suffixExp + data + ' ';
				data = '';
			}
			// 表达式当前项是（
			if (expression[i] === '(') {
				// 添加到
				stack.push(expression[i]);
				continue;
			} else if (expression[i] === ')') {
				while (stack.length > 0) {
					tmp = stack.pop();
					if (tmp === '(') {
						break;
					} else {
						suffixExp = suffixExp + tmp + ' ';
					}
				}
				continue;
			}
			// 运算符;

			if (stack.length === 0) {
				if (['|', '&', '=', '!', '>', '<'].includes(expression[i]) && ['|', '&', '='].includes(expression[i - 1 + 1])) {
					stack.push(expression[i - 1] + expression[i - 1 + 1]);
				} else {
					stack.push(expression[i]);
				}

				continue;
			}
			while (stack.length > 0 && stack[stack.length - 1] !== '(' && priority <= Lxy_expression.getPriority(stack[stack.length - 1])) {
				tmp = stack.pop();
				suffixExp = suffixExp + tmp + ' ';
			}
			if (['|', '&', '=', '!', '>', '<'].includes(expression[i]) && ['|', '&', '='].includes(expression[i - 1 + 1])) {
				stack.push(expression[i - 1] + expression[i - 1 + 1]);
			} else {
				stack.push(expression[i]);
			}
		}

		data = Lxy_expression.trim(data);
		if (data !== '') {
			suffixExp = suffixExp + data + ' ';
		}
		while (stack.length > 0) {
			tmp = stack.pop();
			suffixExp = suffixExp + tmp + ' ';
		}
		return Lxy_expression.trim(suffixExp);
	}
	// expression: 后缀表达式;
	// params    ：参数，key-vaule，表达式中的变量从参数中或者值；
	static calcSuffixExp(expression, params, ifArray, ArrayBind) {
		console.log('ggggggggggg', expression, params, ifArray, ArrayBind);
		// 表达式不存在
		if (expression === null || expression === '') {
			console.log('Calc suffix expression fail, the expression is empty.');
			return null;
		}

		console.log('calcSuffixExp, exp:', expression);
		if (expression[0] === "'") {
			let begin = 1;
			if (expression[1] === "'") {
				begin = 2;
			}
			let end = expression.length;
			if (expression[expression.length - 1] === "'") {
				end--;
			}
			Array.isArray(expression) ? (expression = expression.join('')) : '';
			return this.calcSuffixExp_Str(expression.substring(begin, end), params, ifArray, ArrayBind);
		}

		let varName = '';
		const exps = expression.split(' ');
		if (exps.length === 0) {
			console.log('Calc suffix expression fail, the expression is empty.');
			return null;
		}
		if (exps.length === 1) {
			if (exps[0][0] === '$') {
				if (exps[0].length < 4 && exps[0][1] !== '{') {
					console.log('Calc suffix expression fail, var define is invalid.');
					return null;
				}
				varName = exps[0].substring(2, exps[0].length - 1);
				return params && params.getParam(varName);
			}
		}

		return this.calcSuffixExp_Number(exps, params);
	}
	// 计算前缀表达式
	// expression: 前缀表达式--'$time2View{ReallyTime}'
	// params    ：参数，key-vaule，表达式中的变量从参数中或者值；
	static calPrefixExp(expression, params) {
		console.log('calPrefixExp:', expression, params);
		const exp = this.toSuffixExp(expression);
		return this.calcSuffixExp(exp, params);
	}
	// 计算权重 char 符号
	static getPriority(char) {
		if (char === ')') {
			return 1;
		} else if (char === '||') {
			return 3;
		} else if (char === '&&') {
			return 5;
		} else if (char === '==' || char === '!=') {
			return 7;
		} else if (char === '>' || char === '<' || char === '>=' || char === '<=') {
			return 9;
		} else if (char === '+' || char === '-') {
			return 11;
		} else if (char === '*' || char === '/' || char === '%') {
			return 13;
		} else if (char === '!') {
			return 15;
		} else if (char === '^') {
			return 17;
		} else if (char === '(') {
			return 19;
		}

		return 0;
	}
	static isData(value) {
		// 判断是否是变量或者数字字符串;
		if (value === '' || value.indexOf(' ') > 0) {
			console.log('Data is empty or has space.');
			return false;
		}

		if (value[0] === '$') {
			if (value.length <= 3) {
				console.log('var name is empty.');
				return false;
			}

			if (value[1] !== '{' || value[value.length - 1] !== '}') {
				console.log('var format is invalid.');
				return false;
			}
			return true;
		}

		var regPos = /^\d+(\.\d+)?$/; // 非负浮点数
		var regNeg = /^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$/; // 负浮点数
		if (regPos.test(value) || regNeg.test(value)) {
			return true;
		} else {
			return false;
		}
	}
	// 去除头尾的空格
	static trim(str) {
		let begin = 0; //开始下标
		let end = str.length - 1;
		for (begin = 0; begin < str.length; begin++) {
			if (str[begin] !== ' ') {
				break;
			}
		}
		for (end = str.length - 1; end >= 0; end--) {
			if (str[end] !== ' ') {
				break;
			}
		}
		if (end + 1 <= begin) {
			return '';
		}
		return str.substring(begin, end + 1);
	}
	static calcExp(operator, left, right) {
		console.log('calcExp value', { operator, left, right });
		if (['+', '-', '*', '%', '^', '>', '<', '>=', '<='].includes(operator)) {
			left = Number(left);
			right = Number(right);
			console.log('new calcExp value', { operator, left, right });
		}
		if (operator === '+') {
			return left + right;
		} else if (operator === '-') {
			return left - right;
		} else if (operator === '*') {
			return left * right;
		} else if (operator === '/') {
			return left / right;
		} else if (operator === '%') {
			return left % right;
		} else if (operator === '^') {
			return Math.pow(left, right);
		} else if (operator === '==') {
			return left == right;
		} else if (operator === '!=') {
			return left != right;
		} else if (operator === '>') {
			return left > right;
		} else if (operator === '<') {
			return left < right;
		} else if (operator === '>=') {
			return left >= right;
		} else if (operator === '<=') {
			return left <= right;
		} else if (operator === '||') {
			return left || right;
		} else if (operator === '&&') {
			return left && right;
		} else {
			console.log('Calc suffix expression fail, the operator is not supported, operator: ', operator);
			return -1;
		}
	}

	// 此处将对应的表达式解析为对应的数据
	// ${var} $time2View{var} $label.EnumName{var}
	static calcSuffixExp_Str(exps, params, ifArray, ArrayBind) {
		console.log('calcSuffixExp_Str', exps, params, ifArray, ArrayBind);
		//console.log('[Debug]calcSuffixExp_Str: ', exps)
		if (exps.length === 0) {
			return '';
		}

		let out = ''; // 处理完|中的数据
		let varName = '';
		let posVarFlag = 0; // $符号首次出现的位置
		let posVarBegin = 0;
		let posVarEnd = 0;
		let pos = 0;
		let tmp = '';
		let funcName = '';
		// 循环表达式
		while (pos < exps.length) {
			// 从下标0检索$符号的位置
			posVarFlag = exps.indexOf('$', pos);
			//  $符号不存在
			if (posVarFlag < 0) {
				out += exps.substr(pos);
				if (exps.indexOf('label.') !== 0) {
					break;
				}
			}
			// 获取$符号后面第一个{的位置
			posVarBegin = exps.indexOf('{', posVarFlag + 1);
			// 不存在
			if (posVarBegin < 0) {
				out += exps.substr(pos);
				break;
			}
			// $符号后面第一个}的位置
			posVarEnd = exps.indexOf('}', posVarBegin + 1);
			if (posVarEnd < 0) {
				out += exps.substr(pos);
				break;
			}
			out += exps.substr(pos, posVarFlag - pos);
			pos = posVarEnd + 1;
			varName = exps.substr(posVarBegin + 1, posVarEnd - posVarBegin - 1);
			console.log('mmmmmmmmmmmmm', varName);
			if (exps.startsWith('$getLocalStorage') || exps.startsWith('$getVuex')) {
				funcName = exps.substr(posVarFlag + 1, posVarBegin - posVarFlag - 1);
				const val = callFunc(funcName, varName);
				console.log('callFunc', val);
				return val;
			}
			if (varName === undefined || varName === '') {
				console.error('Calc suffix expression fail, var is empty, exps: ', exps);
				return '';
			}
			if (ifArray) {
				for (let i = 0; i < params._params[ArrayBind].length; i++) {
					tmp = params.getParam(varName, ifArray, ArrayBind);
				}
			} else {
				tmp = params.getParam(varName);
			}
			if (tmp === null) {
				console.error('Calc suffix expression fail, var is undefined, exps: ', exps, varName);
				return '';
			}
			if (posVarBegin <= posVarFlag + 1) {
				// ${var} 格式，获取变量值
				out += tmp;
				continue;
			}
			// $funcName{var} 格式，调用函数，变量值作为函数输入参数
			funcName = exps.substr(posVarFlag + 1, posVarBegin - posVarFlag - 1);
			let res;
			// console.log('eeeeeeeeeeeeeee', funcName, tmp)
			if (ifArray) {
				res = {};
				tmp.forEach((item, index) => {
					res[index] = callFunc(funcName, item);
				});
			} else {
				res = callFunc(funcName, tmp);
			}
			// console.log('888888888888: ', res)
			if (res === undefined || res === null) {
				console.error('Calc suffix expression fail, call func fail, exps: ', exps, funcName, tmp);
				return '';
			}
			ifArray || out.indexOf('label.') === 0 ? (out = res) : (out += res);
		}
		console.log('11111111111111: ', exps, out);
		return out;
	}
	static calcSuffixExp_Number(exps, params) {
		console.log('[Debug]calcSuffixExp_Number: ', exps);
		let varName = '';
		let priority = 0;
		const stack = [];
		let tmp = 0;
		let valueTmp;
		let left = 0;
		let right = 0;
		let operator;
		for (let i = 0; i < exps.length; i++) {
			if (exps[i] === '') {
				console.log('Calc suffix expression fail, data is empty.');
				return null;
			}
			if (['||', '&&', '==', '!=', '>=', '<='].includes(exps[i])) {
				priority = Lxy_expression.getPriority(exps[i]);
			} else {
				priority = Lxy_expression.getPriority(exps[i][0]);
			}

			if (priority === 0) {
				// 操作数入栈;
				if (exps[i][0] === '$') {
					varName = exps[i].substring(2, exps[i].length - 1);
					valueTmp = params.getParam(varName);
					if (valueTmp === null) {
						console.log('[Error]Calc suffix expression fail, the var(', varName, ') isnot exit');
						return null;
					}
					// tmp = parseFloat(valueTmp);
					tmp = valueTmp;
				} else {
					// tmp = parseFloat(exps[i]);
					tmp = exps[i];
				}
				stack.push(tmp);
			} else if (priority === 19) {
				let endIndex, startIndex;
				let del = false;
				let delSum = 0;
				for (let j = 0; j < exps.length; j++) {
					if (del) delSum++;
					if (exps[j].indexOf('(') !== -1) {
						del = true;
						delSum++;
						startIndex = j;
					}
					if (exps[j].indexOf(')') !== -1) {
						endIndex = j + 1;
						break;
					}
				}
				let bracketsArg = exps.slice(i, endIndex);
				bracketsArg[0] = bracketsArg[0].substring(bracketsArg[0].indexOf('(') + 1);
				bracketsArg[bracketsArg.length - 1] = bracketsArg[bracketsArg.length - 1].substring(0, bracketsArg[bracketsArg.length - 1].indexOf(')'));
				exps.splice(startIndex, delSum, this.calcSuffixExp_Number(bracketsArg));
				i -= 2;
			} else {
				operator = i;
				if (stack.length >= 2) {
					right = stack.pop();
					left = stack.pop();
					stack.push(Lxy_expression.calcExp(exps[operator], left, right));
				} else {
					console.error('[Error]Calc suffix expression fail, data not enough');
					return null;
				}
				// right = stack.pop()
				// left = stack.pop()
				// stack.push(Lxy_expression.calcExp(exps[i], left, right))
				// 操作符
				// if (stack.length < 2) {
				// 	console.error('[Error]Calc suffix expression fail, data not enough')
				// 	return null
				// }
			}
		}

		// if (stack.length !== 1) {
		// 	// 表达式无效;
		// 	console.log('[Error]Calc suffix expression fail, expression is invalid')
		// 	return null
		// }
		return stack[0];
	}
}

/**
 * @description: 计算字段的值
 * @param {*} inputDataType 输入参数的类型 1vuex,2固定参数,3本地存储,4表达式
 * @param {*} inputDataName 输入参数的名称 (表达式'$time2View{ReallyTime}')类似这些
 * @param {*} inputData 输入的数据
 * @param {*} pageData 页面的数据
 * @param {*} globalData 全局数据
 * @return {*}
 */
export const calcFieldValue = (inputDataType, inputDataName, inputData, pageData, globalData) => {
	console.log('inputDataTypeinputDataType', inputDataType, inputDataName);
	if (inputDataType && inputDataType >= 1 && inputDataType <= 4) {
		// 固定参数
		if (inputDataType == 2) {
			return inputDataName;
		} else if (inputDataType == 1) {
			// 从vuex
			if (inputDataName) {
				if (inputDataName.startsWith('Vuex.')) {
					const newInputDataName = inputDataName.slice('Vuex.'.length);
					console.log('calcFieldValue', inputDataName);
					return getVuex(newInputDataName);
				} else {
					return getObjAttr(inputData, inputDataName);
				}
			}
		} else if (inputDataType == 3) {
			// 从本地缓存中获取
			const newInputDataName = inputDataName.slice('LocalStorage.'.length);
			return getLocalStorage(newInputDataName);
		} else {
			// 创建一个包含页面数据，输入数据，全局数据的对象
			const datas = new Lxy_params_mgr(pageData, inputData, globalData);
			console.log('inputDataName', inputDataName, '', datas);
			const value = Lxy_expression.calPrefixExp(inputDataName, datas);
			console.log('calPrefixExp111', value);
			if (value === undefined || value === null) {
				console.error('[Error][calcFieldValue]Call exp value for exp field, datas : ', datas, 'express: ', inputDataName);
				return null;
			} else if (typeof value === 'string' && value.indexOf('$label.') === 1) {
				return '';
			} else {
				return value;
			}
		}
	} else {
		console.error('calcFieldValue, unsupport type: ', inputDataType);
		return null;
	}
};

// 得到页面的函数
export const getPageFuncDefine = async (pageid) => {
	// 页面函数
	const funcs = await loadFuncFromLocal(1, pageid)
	if (funcs == null) {
		const res = await httpReqeustApi().SyncPost(
			'/eslithe/queryFunctionDefineNew.action',
			{ PageID: pageid, EntCode: BASE_API.ENT_CODE, Type: 1 },
			{},
			headers
		);
		addFunction(res, 1, pageid);
	} else {
		if (funcs !== 'None') {
			addFunctionLocal(funcs)
		}
	}
	
	
	// 全局函数
	const glfuncs = await loadFuncFromLocal(0, -1)
	if (glfuncs == null) {
		const glres = await httpReqeustApi().SyncPost('/eslithe/queryFunctionDefineNew.action', { EntCode: BASE_API.ENT_CODE, Type: 0 }, {}, headers);
		addFunction(glres, 0, -1);
	} else {
		if (glfuncs !== 'None') {
			addFunctionLocal(glfuncs)
		}
	}
	
	const funcMapTmp = {};
	for (const key in strFuncMap) {
		funcMapTmp[key] = `'${strFuncMap[key]}'`;
	}
	localStorage.setItem('strFuncMap', JSON.stringify(funcMapTmp));
};
// 添加函数
const addFunction = (res, type, page_id) => {
	if (res.success && res.code === '0000') {
		const Records = res.Records || [];
		if (Records.length && Records[0].Functions) {
			const str = Records[0].Functions.replace(/\\n/g, 'ENTER').replace(/\\/g, '');
			console.log('funcTmpStr: ' + str);
			const func = JSON.parse(str);
			console.log('func: ' + func);
			func.forEach((item) => {
				console.log('item.funcText', item.funcText);
				const tmpFunc = item.funcText.replace(/ENTER/g, '\n');
				strFuncMap[item.funcName] = new Function(`return ${tmpFunc}`)();
			});
			if (type === 1) {
				localforage.setItem('page_func_' + BASE_API.ENT_CODE + '_' + type + '_' + page_id, str)
			} else if (type === 0) {
				localforage.setItem('g_func_' + BASE_API.ENT_CODE + '_' + type, str)
			} else if (type === 2) {
				//
			}
		} else {
			// 返回成功，说明没有函数
			if (type === 1) {
				localforage.setItem('page_func_' + BASE_API.ENT_CODE + '_' + type + '_' + page_id, 'None')
			} else if (type === 0) {
				localforage.setItem('g_func_' + BASE_API.ENT_CODE + '_' + type, 'None')
			} else if (type === 2) {
				//
			}
		}
	}
};

const addFunctionLocal = (res) => {
	const func = JSON.parse(res);
	console.log('func: ' + func);
	func.forEach((item) => {
		console.log('item.funcText', item.funcText);
		const tmpFunc = item.funcText.replace(/ENTER/g, '\n');
		strFuncMap[item.funcName] = new Function(`return ${tmpFunc}`)();
	});
}

const loadFuncFromLocal = async (type, page_id) => {
	if (type === 1) {
		const funcs = await localforage.getItem('page_func_' + BASE_API.ENT_CODE + '_' + type + '_' + page_id);
		console.log('loadFuncFromLocal: ', type, page_id, funcs)
		return funcs;
	} else if (type === 0){
		const funcs = await localforage.getItem('g_func_' + BASE_API.ENT_CODE + '_' + type);
		console.log('loadFuncFromLocal: ', type, page_id, funcs)
		return funcs;
	} else {
		return null;
	}
};


export default Lxy_expression;
